package net.ufrog.common.app;

import net.ufrog.common.exception.InvalidArgumentException;
import net.ufrog.common.utils.Objects;
import net.ufrog.common.utils.Strings;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;

/**
 * 验证
 * 
 * @author ultrafrog
 * @version 1.0, 2014-08-24
 * @since 1.0
 */
public class Validation {

    /** 错误映射 */
    private Map<String, List<Error>> errors;

    /** 构造函数 */
    public Validation() {
        errors = new HashMap<>();
    }

    /**
     * 添加错误
     *
     * @param error 错误
     */
    public void addError(Error error) {
        if (!errors.containsKey(error.getName())) {
            errors.put(error.getName(), new ArrayList<>());
        }
        errors.get(error.getName()).add(error);
    }

    /**
     * 读取错误映射
     *
     * @return 错误映射
     * @see #errors
     */
    public Map<String, List<Error>> getErrorMap() {
        return errors;
    }

    /**
     * 读取错误列表
     *
     * @param name 名称
     * @return 错误列表
     */
    public List<Error> getErrors(String name) {
        return errors.get(name);
    }

    /**
     * 读取所有错误
     *
     * @return 所有错误
     */
    public List<Error> getAllErrors() {
        List<Error> errs = new ArrayList<>();
        errors.forEach((k, v) -> errs.addAll(v));
        return errs;
    }

    /**
     * 判断是否存在错误
     *
     * @return 若存在错误返回 <code>true</code><br>否则返回 <code>false</code>
     */
    public Boolean hasErrors() {
        return (errors.size() > 0);
    }

    /**
     * 读取当前验证
     *
     * @return 当前验证
     */
    public static Validation current() {
        return App.current().getValidation();
    }

    /**
     * 添加错误
     *
     * @param error 错误
     */
    public static Error add(Error error) {
        current().addError(error);
        return error;
    }

    /**
     * 添加错误
     *
     * @param message 消息
     * @param name 名称
     * @param args 参数
     */
    public static Error add(String message, String name, Object... args) {
        return add(new Error(message, name, args));
    }

    /**
     * 判断字符串为空
     *
     * @param value 被判断内容
     * @param name 名称
     * @param message 消息
     * @param args 参数
     * @return 错误<br>若没有错误则返回 <code>null</code>
     */
    public static Error isEmpty(String value, String name, String message, Object... args) {
        if (!Strings.empty(value)) {
            return add(message, name, args);
        }
        return null;
    }

    /**
     * 判断字符串非空
     *
     * @param value 被判断内容
     * @param name 名称
     * @param message 消息
     * @param args 参数
     * @return 错误<br>若没有错误则返回 <code>null</code>
     */
    public static Error notEmpty(String value, String name, String message, Object... args) {
        if (Strings.empty(value)) {
            return add(message, name, args);
        }
        return null;
    }

    /**
     * 判断对象为空
     *
     * @param value 被判断内容
     * @param name 名称
     * @param message 消息
     * @param args 参数
     * @return 错误<br>若没有错误则返回 <code>null</code>
     */
    public static Error isNull(Object value, String name, String message, Object... args) {
        if (value != null) {
            return add(message, name, args);
        }
        return null;
    }

    /**
     * 判断对象非空
     *
     * @param value 被判断内容
     * @param name 名称
     * @param message 消息
     * @param args 参数
     * @return 错误<br>若没有错误则返回 <code>null</code>
     */
    public static Error notNull(Object value, String name, String message, Object... args) {
        if (value == null) {
            return add(message, name, args);
        }
        return null;
    }

    /**
     * 判断对象相同
     *
     * @param value 被判断内容
     * @param excepted 期望内容
     * @param name 名称
     * @param message 消息
     * @param args 参数
     * @return 错误<br>若没有错误则返回 <code>null</code>
     */
    public static Error equals(Object value, Object excepted, String name, String message, Object... args) {
        if (!Objects.equals(value, excepted)) {
            return add(message, name, args);
        }
        return null;
    }

    /**
     * 判断对象不同
     *
     * @param value 被判断内容
     * @param excepted 期望内容
     * @param name 名称
     * @param message 消息
     * @param args 参数
     * @return 错误<br>若没有错误则返回 <code>null</code>
     */
    public static Error notEquals(Object value, Object excepted, String name, String message, Object... args) {
        if (Objects.equals(value, excepted)) {
            return add(message, name, args);
        }
        return null;
    }

    /**
     * 判断真
     *
     * @param bool 被判断内容
     * @param name 名称
     * @param message 消息
     * @param args 参数
     * @return 错误<br>若没有错误则返回 <code>null</code>
     */
    public static Error isTrue(Boolean bool, String name, String message, Object... args) {
        if (!bool) {
            return add(message, name, args);
        }
        return null;
    }

    /**
     * 判断假
     *
     * @param bool 被判断内容
     * @param name 名称
     * @param message 消息
     * @param args 参数
     * @return 错误<br>若没有错误则返回 <code>null</code>
     */
    public static Error isFalse(Boolean bool, String name, String message, Object... args) {
        if (bool) {
            return add(message, name, args);
        }
        return null;
    }

    /**
     * 判断电子邮件
     *
     * @param value 被判断内容
     * @param name 名称
     * @param message 消息
     * @param args 参数
     * @return 错误<br>若没有错误则返回 <code>null</code>
     */
    public static Error isEmail(String value, String name, String message, Object... args) {
        if (!Strings.email(value)) {
            return add(message, name, args);
        }
        return null;
    }

    /**
     * 判断正则
     *
     * @param value 被判断内容
     * @param regex 正则表达式
     * @param name 名称
     * @param message 消息
     * @param args 参数
     * @return 错误<br>若没有错误则返回 <code>null</code>
     */
    public static Error regex(String value, String regex, String name, String message, Object... args) {
        if (!Pattern.compile(regex).matcher(value).find()) {
            return add(message, name, args);
        }
        return null;
    }

    /**
     * 所有错误
     *
     * @return 错误
     */
    public static Map<String, List<Error>> errors() {
        return Validation.current().getErrorMap();
    }

    /** 检查错误<br>若有非法参数则抛出异常 */
    public static void checkErrors() {
        if (Validation.current().hasErrors()) {
            throw new InvalidArgumentException();
        }
    }

    /**
     * 验证错误
     *
     * @author ultrafrog
     * @version 1.0, 2014-08-24
     * @since 1.0
     */
    public static class Error {

        /** 错误信息 */
        private String message;

        /** 名称<br>对应输入项 */
        private String name;

        /** 消息参数 */
        private Object[] args;

        /** 构造函数 */
        public Error() {}

        /**
         * 构造函数
         *
         * @param message 错误信息
         * @param name 名称
         */
        public Error(String message, String name) {
            this.message = message;
            this.name = name;
        }

        /**
         * 构造函数
         *
         * @param message 错误信息
         * @param name 名称
         * @param args 参数
         */
        public Error(String message, String name, Object... args) {
            this(message, name);
            this.args = args;
        }

        /**
         * 读取错误信息
         *
         * @return 错误信息
         * @see #message
         */
        public String getMessage() {
            return App.message(message, args);
        }

        /**
         * 设置错误信息
         *
         * @param message 错误信息
         * @see #message
         */
        public void setMessage(String message) {
            this.message = message;
        }

        /**
         * 读取名称
         *
         * @return 名称
         * @see #name
         */
        public String getName() {
            return name;
        }

        /**
         * 设置名称
         *
         * @param name 名称
         * @see #name
         */
        public void setName(String name) {
            this.name = name;
        }

        /**
         * @return 原始消息
         */
        public String getOriginalMessage() {
            return message;
        }
    }
}
